{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Numpy\n",
    "NumPy（Numerical Python的简称），是科学计算基础的一个库，提供了大量关于科学计算的相关功能，例如，线性变换，数据统计，随机数生成等。其提供的最核心的类型为多维数组类型（ndarray）。\n",
    "\n",
    "## 使用方式\n",
    "可以使用如下的方式来安装numpy库：  \n",
    "`pip install numpy`  \n",
    "根据惯例，使用numpy库的导入方式为：  \n",
    "`import numpy as np`  \n",
    "在导入之后，我们可以通过：  \n",
    "`np.__version__`  \n",
    "来查看Numpyu库的版本信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.11.1\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "# In与Out都是IPython的特殊对象。用来存储我们输入与输出的值。\n",
    "# In是列表类型，Out是字典类型。\n",
    "# print(np.__version__)\n",
    "\n",
    "# 如果不使用print输出，而是作为表达式计算值显示时，我们只能看到最后一个结果。\n",
    "print(np.__version__)\n",
    "print(5 + 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数组的创建\n",
    "Numpy提供了很多方式（函数）来创建数组对象，常用的方式如下：\n",
    "* array\n",
    "* arange\n",
    "* ones / ones_like\n",
    "* zeros / zeros_like\n",
    "* empty / empty_like\n",
    "* full / full_like\n",
    "* eye / identity\n",
    "* linspace\n",
    "* logspace\n",
    "\n",
    "说明：\n",
    "* 注意arange函数，不是arrange。\n",
    "* arange与linspace的区别。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display\n",
    "# numpy最核心的类型，就是多维数组类型numpy.ndarray。\n",
    "# 传递一个列表（list），创建数组\n",
    "n = np.array([1, 2, 3])\n",
    "print(n)\n",
    "\n",
    "# 在输出显示时，优先使用display，这样可以比print显示更加友好。【与Out对象中显示的格式是一样的。】\n",
    "display(5 + 3)\n",
    "display(n)\n",
    "\n",
    "# 创建多维数组\n",
    "n = np.array([[1, 2], [3, 4], [5, 6]])\n",
    "display(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 5,  7,  9, 11, 13])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([2. , 1.9, 1.8, 1.7, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 类似与python中的range函数。\n",
    "n = np.arange(10)\n",
    "display(n)\n",
    "n = np.arange(5, 15)\n",
    "display(n)\n",
    "\n",
    "# 指定步长\n",
    "n = np.arange(5, 15, 2)\n",
    "display(n)\n",
    "\n",
    "# 不同于range，arange的步长还支持浮点类型。\n",
    "n = np.arange(1, 2, 0.1)\n",
    "display(n)\n",
    "\n",
    "# 步长也可以为负值。\n",
    "n = np.arange(2, 1, -0.1)\n",
    "display(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 1., 1., 1.],\n",
       "       [1., 1., 1., 1.],\n",
       "       [1., 1., 1., 1.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 1],\n",
       "       [1, 1]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8,  9],\n",
       "       [10, 11, 12, 13, 14],\n",
       "       [15, 16, 17, 18, 19]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 1, 1, 1, 1],\n",
       "       [1, 1, 1, 1, 1],\n",
       "       [1, 1, 1, 1, 1],\n",
       "       [1, 1, 1, 1, 1]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8,  9],\n",
       "       [10, 11, 12, 13, 14],\n",
       "       [15, 16, 17, 18, 19]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0],\n",
       "       [0, 0, 0, 0, 0]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 创建值全为1的数组。\n",
    "n = np.ones((3, 4))\n",
    "display(n)\n",
    "n = np.array([[1, 2], [3, 4]])\n",
    "display(n)\n",
    "\n",
    "# 创建一个与参数数组形状相同的数组，值全为1。\n",
    "x = np.ones_like(n)\n",
    "display(x)\n",
    "\n",
    "# 创建全为0的数组。\n",
    "x = np.zeros((2, 5))\n",
    "x = np.arange(20).reshape(4,5)\n",
    "y1 = np.ones_like(x)\n",
    "y2 = np.zeros_like(x)\n",
    "display(x, y1, y2)\n",
    "\n",
    "# 创建值全为空的数组。（值并非是为空，而是值尚未经过初始化）\n",
    "x = np.empty(3)\n",
    "x = np.arange(20).reshape(4,5)\n",
    "y = np.empty_like(x)\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 2.,  2.,  2.,  2.],\n",
       "       [ 2.,  2.,  2.,  2.],\n",
       "       [ 2.,  2.,  2.,  2.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 33.,  33.,  33.,  33.],\n",
       "       [ 33.,  33.,  33.,  33.],\n",
       "       [ 33.,  33.,  33.,  33.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 1.,  1.,  1.,  1.],\n",
       "       [ 1.,  1.,  1.,  1.],\n",
       "       [ 1.,  1.,  1.,  1.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 1.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  1.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  1.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  1.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  1.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 1.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  1.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  1.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  1.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  1.]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,\n",
       "        12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,  21.,  22.,\n",
       "        23.,  24.,  25.,  26.,  27.,  28.,  29.,  30.,  31.,  32.,  33.,\n",
       "        34.,  35.,  36.,  37.,  38.,  39.,  40.,  41.,  42.,  43.,  44.,\n",
       "        45.,  46.,  47.,  48.,  49.,  50.])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([   2.        ,    2.73208051,    3.73213197,    5.09824251,\n",
       "          6.96440451,    9.51365692,   12.99603834,   17.75311155,\n",
       "         24.25146506,   33.12847756,   45.254834  ,   61.81992505,\n",
       "         84.44850629,  115.36005921,  157.58648491,  215.2694823 ,\n",
       "        294.06677888,  401.70705812,  548.74801282,  749.61187632])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 创建指定值的数组\n",
    "x = np.full((3, 4), 2.)\n",
    "y = np.full_like(x, 33)\n",
    "display(x, y)\n",
    "display(np.ones((3, 4)))\n",
    "\n",
    "# 创建单位矩阵\n",
    "display(np.eye(5))\n",
    "display(np.identity(5))\n",
    "\n",
    "# 创建等差数列的数组。\n",
    "# num指定数组元素的个数。endpoint指定是否包含终止点。（默认为True，包含）\n",
    "display(np.linspace(1, 50, num=50, endpoint=True))\n",
    "\n",
    "# 创建等比数列的数组。（前面两个参数指定指数）\n",
    "# num指定数组元素的个数。endpoint指定是否包含终止点。\n",
    "# base用来指定底数，默认为10。\n",
    "display(np.logspace(1, 10, num=20, endpoint=False, base=2))\n",
    "\n",
    "# 说明：\n",
    "# 注意：arange与linspace。\n",
    "# 二者都可以产生一系列区间值。\n",
    "# 对于arange，更关注的是数值之间的间隔（步长）是多少，而不太关注具体会产生多少数值。\n",
    "# 对于linspace，更关注的是数值的个数，而不太关注数值之间的距离是多少。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数组（ndarray）与列表（List）\n",
    "数组与列表类似，是具有相同类型的多个元素构成的整体。  \n",
    "局限：\n",
    "* 数组元素要求是相同类型，而列表的元素可以是不同类型。\n",
    "\n",
    "优势：\n",
    "* 数组可以与标量进行运算，数组之间也可以进行矢量化运算。【对应位置的元素进行运算，无需进行循环操作。这样就可以充分利用现代处理器SIMD Single Instruction,Multiple Data的方式进行并行计算】。\n",
    "* 数组在运算时，具有广播能力。【可根据需要进行元素的扩展，完成运算。】\n",
    "* 数组底层使用C程序编写，运算速度快。\n",
    "* 数组底层使用C中数组的存储方式（紧凑存储），节省内存空间。\n",
    "\n",
    "## 应用对比\n",
    "* 将两个等长的列表（数组）分别进行数学运算（例如，+, -等）。\n",
    "* 将一个列表（数组）中的所有元素进行相同的改变。\n",
    "* 对步骤2进行计时，衡量时间消耗。（练习）\n",
    "* 创建相同大小的列表（数组），衡量内存消耗。（练习）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[16, 17, 15]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([17, 18, 16])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([27, 38, 46])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([18, 19, 17])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[11, 22, 33],\n",
       "       [11, 22, 33]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 班级中每个学生的年龄\n",
    "# 如果是列表，则需要进行循环的操作。\n",
    "li = [15, 16, 14]\n",
    "for i in range(len(li)):\n",
    "    li[i] += 1\n",
    "display(li)\n",
    "\n",
    "# 如果是ndarray数组，则无需循环，直接进行矢量化运算。\n",
    "a = np.array([15, 16, 14])\n",
    "a = a + 1\n",
    "# 数组可以与标量执行运行。【实际上会扩散到数组中每个元素与该标量执行运算。】\n",
    "a += 1\n",
    "display(a)\n",
    "\n",
    "# 数组之间也可以进行矢量化运算。\n",
    "# 此时，就是数组中对应元素执行相应的运算。\n",
    "b = np.array([10, 20, 30])\n",
    "display(a + b)\n",
    "\n",
    "# ndarray数组具有广播的能力。\n",
    "# 数组与标量运算，实现的广播。\n",
    "a += 1\n",
    "display(a)\n",
    "\n",
    "# 数组与数组之间，实现的广播。\n",
    "c = np.array([[1, 2, 3], [1, 2, 3]])\n",
    "display(b + c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5, 7, 9]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([5, 7, 9])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 对列表执行运算，需要使用循环\n",
    "li1 = [1, 2, 3]\n",
    "li2 = [4, 5, 6]\n",
    "li3 = []\n",
    "for x, y in zip(li1, li2):\n",
    "    li3.append(x + y)\n",
    "print(li3)\n",
    "\n",
    "a = np.array([1, 2, 3])\n",
    "b = np.array([4, 5, 6])\n",
    "c = a + b\n",
    "display(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.54 ms ± 9.43 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit li = list(range(100000))\n",
    "for i in range(len(li)):\n",
    "    li[i] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "29.3 µs ± 31.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit a = np.arange(100000)\n",
    "a += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%load_ext memory_profiler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%%writefile test.py\n",
    "import numpy as np\n",
    "\n",
    "def m():\n",
    "    li = list(range(100000))\n",
    "    a = np.arange(100000)\n",
    "    del li\n",
    "    del a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%mprun -f test.m test.m()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## <font color=\"green\">为什么数组会比列表快，而且快很多？</font>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 相关属性与操作\n",
    "数组对象具有如下常用属性：\n",
    "* ndim\n",
    "* shape\n",
    "* dtype\n",
    "* size\n",
    "* itemsize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(2, 3)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "dtype('int32')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.array([[1, 2, 3], [3, 4, 5]])\n",
    "# 获取数组的维度\n",
    "display(x.ndim)\n",
    "# 获取数组的形状（每个维度上的长度）。返回一个元组。\n",
    "display(x.shape)\n",
    "# 获取数组的元素类型。\n",
    "display(x.dtype)\n",
    "# 返回数组元素的个数。(整体所有元素的个数)\n",
    "display(x.size)\n",
    "# 返回数组元素占用空间的大小。以字节为单位。\n",
    "display(x.itemsize)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据类型\n",
    "* 在创建数组时，也可以使用dtype来显式指定数组中元素的类型（通过numpy提供的类型进行指定）。\n",
    "* 如果没有指定，则会根据元素类型进行推断。\n",
    "* 如果元素的类型不同，则会选择一种兼容的类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('<U32')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "dtype('<U3')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "dtype('float32')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 如果创建时没有指定元素的类型，则会根据现有元素，自动推断元素类型。\n",
    "# u32表示32位无符号char值\n",
    "x = np.array([1, 2, 3., \"abc\"])\n",
    "display(x.dtype)\n",
    "\n",
    "# 注意：不同的数据顺序，可能会影响到最终的数组类型。\n",
    "y = np.array([\"abc\", 1, 2, 3.])\n",
    "display(y.dtype)\n",
    "\n",
    "# 在数据存储上，有两种形式：\n",
    "# 1 高位优先 >\n",
    "# 2 低维优先 <\n",
    "# 我们在创建数组时，可以使用dtype参数显式指定数组的类型。\n",
    "w = np.array([1, 2, 3], dtype=np.float32)\n",
    "display(w.dtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类型转换\n",
    "我们可以通过数组对象的astype函数来进行类型转换。\n",
    "## <font color=\"green\">是否可以直接修改dtype属性进行类型转换？</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 1,  2,  3, -1, -1, -1], dtype=int64)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([          0,  1073217536,  1717986918,  1073899110,   858993459,\n",
       "        1074475827,   858993459, -1074580685,  -858993459, -1073951540,\n",
       "                 0, -1074266112])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.array([1.5, 2.3, 3.4, -1.2, -1.8, -1.5])\n",
    "display(x.dtype)\n",
    "y = x.astype(np.int64)\n",
    "display(y)\n",
    "\n",
    "# 直接修改dtype属性，尝试修改数组类型。\n",
    "x.dtype = np.int\n",
    "display(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 改变形状\n",
    "我们可以通过数组对象的reshape方法（或者np的reshape函数）来改变数组的形状。  \n",
    "\n",
    "说明：\n",
    "* 改变数组形状时，如果维度大于1，可以将某一个维度设置为-1。\n",
    "* numpy中存在很多方法，既可以使用np来访问，也可以通过数组对象来访问。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[0, 1],\n",
       "       [2, 3],\n",
       "       [4, 5],\n",
       "       [6, 7],\n",
       "       [8, 9]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(10,)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(2, 5)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3, 4],\n",
       "       [5, 6, 7, 8, 9]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4,  5],\n",
       "       [ 6,  7,  8,  9, 10, 11],\n",
       "       [12, 13, 14, 15, 16, 17],\n",
       "       [18, 19, 20, 21, 22, 23],\n",
       "       [24, 25, 26, 27, 28, 29]])"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(10)\n",
    "display(x)\n",
    "\n",
    "# numpy中，提供了很多功能函数，既可以通过np的方式调用，也可以通过ndarray数组对象来进行调用。\n",
    "y = np.reshape(x, (5, 2))\n",
    "display(y)\n",
    "\n",
    "# 通过数组对象调用reshape，shape形状参数，我们既可以传一个元组，也可以分开传入。\n",
    "# 通过np方式调用reshape，只能通过元组形式传入。\n",
    "y = x.reshape(2, 5)\n",
    "display(x.shape, y.shape)\n",
    "\n",
    "# 不建议这样做\n",
    "x.shape = (2, 5)\n",
    "display(x)\n",
    "\n",
    "# 级联操作\n",
    "np.arange(30).reshape(5, 6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 索引与切片\n",
    "在Python中，序列类型支持索引与切片操作，在numpy库中，ndarray数组也支持类似的操作。不过，二者之间既有相同点，也有不同点。\n",
    "### 相似点\n",
    "数组对象也支持索引与切片操作，语法与Python中序列类型的索引与切片相似。  \n",
    "当数组是多维数组时，可以使用array\\[高维, 低维\\]的方式按维度进行索引或切片。  \n",
    "### 不同点\n",
    "数组的切片返回的是原数组数据的视图（回忆：Python中呢？）。如果需要复制底层的数组元素，可以使用数组对象的copy方法。  \n",
    "注意：视图是共享底层的数组元素，但视图并不是赋值。\n",
    "\n",
    "思考：通过切片，我们可以选取多个元素，但是，如果我们要选取的低维数组（或元素）是不连续的，该怎样做？\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4,  5],\n",
       "       [ 6,  7,  8,  9, 10, 11],\n",
       "       [12, 13, 14, 15, 16, 17],\n",
       "       [18, 19, 20, 21, 22, 23],\n",
       "       [24, 25, 26, 27, 28, 29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[29, 28, 27, 26, 25, 24],\n",
       "       [23, 22, 21, 20, 19, 18],\n",
       "       [17, 16, 15, 14, 13, 12],\n",
       "       [11, 10,  9,  8,  7,  6],\n",
       "       [ 5,  4,  3,  2,  1,  0]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[100, 2, 3, 4, 5]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 5]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.arange(30).reshape(5, 6)\n",
    "display(x)\n",
    "display(x[1][2])\n",
    "\n",
    "# 也可以这样获取元素\n",
    "display(x[1, 2])\n",
    "\n",
    "# 切片,是第一个维度的数据，都倒过来\n",
    "y = x[::-1, ::-1]\n",
    "display(y)\n",
    "\n",
    "li = [1, 2, 3, 4, 5]\n",
    "# python中，切片是浅拷贝。\n",
    "li2 = li[:]\n",
    "li[0] = 100\n",
    "display(li, li2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[2000,    1,    2],\n",
       "       [   6,    7,    8],\n",
       "       [  12,   13,   14]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[2000,    1,    2,    3,    4,    5],\n",
       "       [   6,    7,    8,    9,   10,   11],\n",
       "       [  12,   13,   14,   15,   16,   17],\n",
       "       [  18,   19,   20,   21,   22,   23],\n",
       "       [  24,   25,   26,   27,   28,   29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[2000,    1,    2],\n",
       "       [   6,    7,    8],\n",
       "       [  12,   13,   14]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "y = x[0:3, 0:3]\n",
    "display(y)\n",
    "# x[0][0] = 1000\n",
    "y[0][0] = 2000\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[2000,    1,    2,    3,    4,    5],\n",
       "       [   6,    7,    8,    9,   10,   11],\n",
       "       [  12,   13,   14,   15,   16,   17],\n",
       "       [  18,   19,   20,   21,   22,   23],\n",
       "       [  24,   25,   26,   27,   28,   29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1000,    1,    2,    3,    4,    5],\n",
       "       [   6,    7,    8,    9,   10,   11],\n",
       "       [  12,   13,   14,   15,   16,   17],\n",
       "       [  18,   19,   20,   21,   22,   23],\n",
       "       [  24,   25,   26,   27,   28,   29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 注意，ndarray数组切片，返回的是原数据的视图。\n",
    "# 但是，这种视图是共享底层的数据，并不是一种赋值。\n",
    "\n",
    "y = x[:]\n",
    "print(x is y)\n",
    "\n",
    "# 可以通过数组对象的copy方法，实现底层数据的复制，而不是返回底层数据的视图。\n",
    "y = x.copy()\n",
    "x[0][0] = 2000\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过整数数组进行索引\n",
    "当要选取的元素不连续时，可以提供一个索引数组来选择（或修改）对应索引位置的元素。\n",
    "\n",
    "说明：\n",
    "* 通过整数数组索引，返回的是原数组的拷贝，而不是视图。\n",
    "* 可以提供多个一维数组索引，此时会将每个数组的对应位置元素作为索引，返回对应的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 6,  7,  8,  9, 10, 11],\n",
       "       [18, 19, 20, 21, 22, 23]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4,  5],\n",
       "       [ 6,  7,  8,  9, 10, 11],\n",
       "       [12, 13, 14, 15, 16, 17],\n",
       "       [18, 19, 20, 21, 22, 23],\n",
       "       [24, 25, 26, 27, 28, 29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[2000,    7,    8,    9,   10,   11],\n",
       "       [  18,   19,   20,   21,   22,   23]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 1, 15, 22])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(30).reshape(5, 6)\n",
    "# display(x)\n",
    "# index = [1, 3, 4]\n",
    "# display(x[index])\n",
    "# display(x[0:2])\n",
    "# display(x[[0, 1]])\n",
    "\n",
    "# 通过整数数组，进行索引（提取元素），返回的是原数组数据的拷贝，而不是视图。（这点与切片不同）\n",
    "y = x[[1, 3]]\n",
    "display(y)\n",
    "y[0, 0] = 2000\n",
    "display(x, y)\n",
    "\n",
    "# 提供多个一维数组，提取（获取）元素。\n",
    "# 每个一维数组指定相应维度的索引（坐标）。\n",
    "x[[0, 2, 3], [1, 3, 4]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过布尔数组进行索引\n",
    "我们可以提供一个布尔类型的数组（A），然后通过该数组（A）来对另外一个数组（B）进行索引（元素选取）。索引的原则为：如果为True，则选取对应位置的元素，否则不选取。<br>\n",
    "通过布尔类型的数组进行索引是常见且实用的操作，我们通常用来进行元素选择（或过滤）操作。例如：\n",
    "* 选择一个公司中所有年龄大于15的年龄。\n",
    "* 选择两个数组中对应位置相同的元素。\n",
    "* 将所有大于100的值设置为100。\n",
    "\n",
    "说明：\n",
    "* 用于索引的布尔数组通常通过现有数组计算得出。\n",
    "* 可以通过~对条件进行取反操作（不能使用not）。\n",
    "* 当存在多个条件时，可以使用&，|符号（不能使用and与or）,同时，每个条件需要使用()进行括起。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10, 11, 12, 13, 14],\n",
       "       [15, 16, 17, 18, 19],\n",
       "       [20, 21, 22, 23, 24],\n",
       "       [25, 26, 27, 28, 29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[10, 11, 12, 13, 14],\n",
       "       [20, 21, 22, 23, 24]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[False, False, False, False, False],\n",
       "       [False,  True,  True,  True,  True],\n",
       "       [ True,  True,  True,  True,  True],\n",
       "       [ True,  True,  True,  True,  True]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 1, 10])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 1, 10])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([102, 234, 120])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 100,   -3,  234,  100, -123,   50])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 100,   -3,  100, -123,   50])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.arange(10,30).reshape(4, 5)\n",
    "display(x)\n",
    "# 我们可以通过布尔类型数组（列表）来选择元素。依据：如果是True，则提取（保留），如果是False，则去掉。\n",
    "display(x[[True, False, True, False]])\n",
    "display(x > 15)\n",
    "\n",
    "a = np.array([1, 3, 9, 10])\n",
    "b = np.array([1, 8, 6, 10])\n",
    "display(a[[True, False, False, True]])\n",
    "display(a[a == b])\n",
    "a = np.array([102, -3, 234, 120, -123, 50])\n",
    "display(a[a > 100])\n",
    "\n",
    "\n",
    "# 在numpy中，实现Python中的and，or，与not\n",
    "# and ->  &\n",
    "# or  ->  |\n",
    "# not -> ~\n",
    "# 注意：在进行条件组合的时候，每个条件使用小括号括起。【别再看运算符优先级了，此处不适用。】\n",
    "a[(a > 100) & (a < 150)] = 100\n",
    "display(a)\n",
    "b = a[~(a > 100)]\n",
    "display(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数组扁平化\n",
    "我们可以通过调用ravel或flatten方法，对数组对象进行扁平化处理。\n",
    "* np.ravel / ravel\n",
    "* flatten\n",
    "\n",
    "二者的区别在于，ravel返回原数组的视图，而flatten返回原数组的拷贝。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1],\n",
       "        [ 2,  3]],\n",
       "\n",
       "       [[ 4,  5],\n",
       "        [ 6,  7]],\n",
       "\n",
       "       [[ 8,  9],\n",
       "        [10, 11]]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.arange(12).reshape(3, 2, 2)\n",
    "display(x)\n",
    "display(x.ravel())\n",
    "display(np.ravel(x))\n",
    "display(x.flatten())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[1000,    1],\n",
       "        [   2,    3]],\n",
       "\n",
       "       [[   4,    5],\n",
       "        [   6,    7]],\n",
       "\n",
       "       [[   8,    9],\n",
       "        [  10,   11]]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([1000,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,\n",
       "         11])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[[1000,    1],\n",
       "        [   2,    3]],\n",
       "\n",
       "       [[   4,    5],\n",
       "        [   6,    7]],\n",
       "\n",
       "       [[   8,    9],\n",
       "        [  10,   11]]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([2000,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,\n",
       "         11])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 二者的区别在于，ravel返回原数组的视图，而flatten返回原数组的拷贝。\n",
    "y = x.ravel()\n",
    "y[0] = 1000\n",
    "display(x, y)\n",
    "\n",
    "y = x.flatten()\n",
    "y[0] = 2000\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数组的存储顺序\n",
    "\n",
    "在创建数组时，我们可以通过order参数来指定数组元素的存储顺序。存储顺序分为四种：\n",
    "* C 行优先\n",
    "* F 列优先\n",
    "* K\n",
    "* A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8],\n",
       "       [ 9, 10, 11, 12]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 1,  4,  7, 10],\n",
       "       [ 2,  5,  8, 11],\n",
       "       [ 3,  6,  9, 12]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.array(range(1,13)).reshape((3, 4), order=\"C\")\n",
    "y = np.array(range(1,13)).reshape((3, 4), order=\"F\")\n",
    "display(x)\n",
    "display(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## <font color=\"green\">练习</font>\n",
    "<font color=\"green\">1 直接使用array去创建一个多维数组（如2 \\* 2），order分别设置为C与F，二者会有不同吗？  \n",
    "2 创建一个2 \\* 3（3 \\* 2）的数组，将其reshape为3 \\* 2（2 \\* 3），order分别设置为C与F，解释结果。</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.array([[1, 2], [3, 4], [5, 6]], order=\"C\")\n",
    "y = np.array([[1, 2], [3, 4], [5, 6]], order=\"F\")\n",
    "\n",
    "# order 影响两方面，一是数据抽取（扁平化处理）的顺序。二是数据构建（数组填充）的顺序。\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 5],\n",
       "       [4, 3],\n",
       "       [2, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 3],\n",
       "       [4, 5, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[1, 5, 4],\n",
       "       [3, 2, 6]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "x = x.reshape(3, 2, order=\"C\")\n",
    "y = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "display(y)\n",
    "y = y.reshape(3, 2, order=\"F\")\n",
    "display(x, y)\n",
    "\n",
    "x = np.array([[1, 2], [3, 4], [5, 6]])\n",
    "x = x.reshape(2, 3, order=\"C\")\n",
    "y = np.array([[1, 2], [3, 4], [5, 6]])\n",
    "y = y.reshape(2, 3, order=\"F\")\n",
    "display(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们在创建数组时，在读取（解析）现有的数据顺序，以及创建新的数据的结构上，都会使用order指定的顺序。\n",
    "\n",
    "可以简单认为，我们先使用指定的order将原数据扁平化处理，然后在使用指定的order顺序去构建新的数组（向新的数组中插入值）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通用函数ufunc（universal function）\n",
    "Numpy提供了许多通用函数，这些通用函数可以看做是以前通过Python计算的矢量化版本。\n",
    "\n",
    "* abs / fabs\n",
    "* ceil / floor\n",
    "* exp\n",
    "* log / log2 / log10\n",
    "* modf\n",
    "* sin / sinh / cos / cosh\n",
    "* sqrt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 1, 2, 3, 4])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(array([ 0.3,  0.5, -0. ,  0. ,  0.5]), array([  1.,   2., -10.,   3.,   5.]))"
      ]
     },
     "execution_count": 124,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([1, 2, 3, 4, -1, -2, -3, -4])\n",
    "y = np.abs(x)\n",
    "display(y)\n",
    "\n",
    "y = np.array([1.3, 2.5, -10, 3, 5.5])\n",
    "# 返回一个元组，含有两个元素（数组类型），第一个元素返回小数部分，第二个元素返回整数部分。\n",
    "np.modf(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 统计函数\n",
    "Numpy（或数组对象）具有如下常用的统计函数。  \n",
    "* mean / sum\n",
    "* max / min\n",
    "* argmax / argmin\n",
    "* std / var\n",
    "* cumsum / cumprod\n",
    "\n",
    "### 轴（axis）\n",
    "可以指定axis参数来改变统计的轴。axis是一个非常重要的参数，关于数组的很多操作与运算，都涉及该参数。轴的取值为0,1,2……其中0表示最高的维度，1表示次高的维度，以此类推。同时，轴也可以为负值，表示倒数第n个维度，例如，-1表示最后（低）一个维度。在二维数组中，0表示沿着竖直方向进行操作，1表示沿着水平方向进行操作。在多维数组中，轴相对复杂一些，可以认为，是沿着轴所指定的下标变化的方向，进行操作。例如，如果轴是1，则根据第1个下标变化的方向上进行操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3,  4,  5],\n",
       "       [ 6,  7,  8,  9, 10]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "5.5"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "55"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "2.8722813232690143"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "8.25"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([ 1,  3,  6, 10, 15, 21, 28, 36, 45, 55], dtype=int32)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([      1,       2,       6,      24,     120,     720,    5040,\n",
       "         40320,  362880, 3628800], dtype=int32)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.arange(1,11).reshape(2, 5)\n",
    "display(x)\n",
    "\n",
    "# 平均值，\n",
    "display(np.mean(x), np.sum(x))\n",
    "display(np.max(x), np.min(x))\n",
    "\n",
    "# 返回最大值（最小值）的索引。\n",
    "display(np.argmax(x), np.argmin(x))\n",
    "\n",
    "# 标准差， 方差\n",
    "display(np.std(x), np.var(x))\n",
    "\n",
    "# 求累积和与累积乘积\n",
    "display(np.cumsum(x), np.cumprod(x))\n",
    "# 如果没有指定额外参数，统计函数就相当于对整个数组所有元素进行统计。（将数组扁平化处理，然后对所有元素进行操作。）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10,  9,  8,  7,  6],\n",
       "       [ 5,  4,  3,  2,  1]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([15, 13, 11,  9,  7])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([40, 15])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([40, 15])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8,  9],\n",
       "       [10, 11, 12, 13, 14],\n",
       "       [15, 16, 17, 18, 19],\n",
       "       [20, 21, 22, 23, 24],\n",
       "       [25, 26, 27, 28, 29]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 在统计的时候，我们可以指定轴的方向，来进行统计。\n",
    "x = np.arange(10, 0, -1).reshape(2, 5)\n",
    "display(x)\n",
    "\n",
    "# 按竖直方向统计\n",
    "display(np.sum(x, axis=0))\n",
    "\n",
    "# 按水平方向统计\n",
    "display(np.sum(x, axis=1))\n",
    "display(np.sum(x, axis=-1))\n",
    "\n",
    "# reshape形状是多维时，可以将其中一个维度指定为-1，表示根据其他维度的大小，来自动计算该维度的大小。【至多只能有一个-1。】\n",
    "x = np.arange(30).reshape(6, -1)\n",
    "display(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7],\n",
       "        [ 8,  9, 10, 11]],\n",
       "\n",
       "       [[12, 13, 14, 15],\n",
       "        [16, 17, 18, 19],\n",
       "        [20, 21, 22, 23]]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[12, 14, 16, 18],\n",
       "       [20, 22, 24, 26],\n",
       "       [28, 30, 32, 34]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[12, 15, 18, 21],\n",
       "       [48, 51, 54, 57]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "array([[ 6, 22, 38],\n",
       "       [54, 70, 86]])"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "x = np.arange(24).reshape(2, 3, 4)\n",
    "display(x)\n",
    "display(x.sum(axis=0))\n",
    "display(x.sum(axis=1))\n",
    "display(x.sum(axis=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 随机函数\n",
    "* np.random.rand\n",
    "* np.random.random 与rand相同，但是形状通过一个参数指定。\n",
    "* np.random.randn\n",
    "* np.random.normal\n",
    "* np.random.randint\n",
    "* np.random.seed\n",
    "* np.random.shuffle\n",
    "* np.random.uniform"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 连接与拆分函数\n",
    "* np.concatenate 对多个数组按指定轴的方向进行连接。\n",
    "* np.vstack / np.hstack\n",
    "* np.split / np.hsplit / np.vsplit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.17421631534553328"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x = np.random.uniform()\n",
    "display(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 其他函数（方法）\n",
    "* any / all\n",
    "* transpose（T）\n",
    "* dot（@）\n",
    "* sort / np.sort\n",
    "* unique\n",
    "* np.where\n",
    "* np.save / np.load\n",
    "* np.savetxt / np.loadtxt\n",
    "\n",
    "说明：\n",
    "* sort可以指定排序的轴。\n",
    "* save在保存数组时，如果没有指定扩展名，则自定补充.npy作为扩展名。\n",
    "## <font color=\"green\">数据对象与numpy都具有sort方法（函数），二者等价吗？</font>"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
